package com.lyu.xiaolvshu.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.common.base.Preconditions;
import com.lyu.framework.biz.context.holder.LoginUserContextHolder;
import com.lyu.framework.common.exception.BizException;
import com.lyu.framework.common.response.Response;
import com.lyu.framework.common.util.JsonUtils;
import com.lyu.xiaolvshu.auth.constant.RedisKeyConstants;
import com.lyu.xiaolvshu.auth.enums.LoginTypeEnum;
import com.lyu.xiaolvshu.auth.enums.ResponseCodeEnum;
import com.lyu.xiaolvshu.auth.model.vo.user.UpdatePasswordReqVO;
import com.lyu.xiaolvshu.auth.model.vo.user.UserLoginReqVO;
import com.lyu.xiaolvshu.auth.rpc.UserRpcService;
import com.lyu.xiaolvshu.auth.service.AuthService;
import com.lyu.xiaolvshu.user.dto.resp.FindUserByPhoneRespDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
@Slf4j
public class AuthServiceImpl implements AuthService {

    @Resource
    private UserRpcService userRpcService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        String phone = userLoginReqVO.getPhone();
        Integer type = userLoginReqVO.getType();

        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);

        if (Objects.isNull(loginTypeEnum)) {
            throw new BizException(ResponseCodeEnum.LOGIN_TYPE_ERROR);
        }

        Long userId = null;
        switch (Objects.requireNonNull(loginTypeEnum)) {
            case VERIFICATION_CODE -> {
                // 验证码登陆
                String verificationCode = userLoginReqVO.getCode();

                Preconditions.checkArgument(StringUtils.isNoneBlank(verificationCode), "验证码不能为空");

                String key = RedisKeyConstants.buildVerificationCodeKey(phone);
                String sentCode = (String) redisTemplate.opsForValue().get(key);
                if (!StringUtils.equals(verificationCode, sentCode)) {
                    throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                }

                FindUserByPhoneRespDTO userDO = userRpcService.findUserByPhone(phone);
                if (log.isDebugEnabled()) {
                    log.debug("==> 用户是否注册, phone: {}, userDO: {}", phone, JsonUtils.toJsonString(userDO));
                }

                // 判断用户是否注册
                if (Objects.isNull(userDO)) {
                    userId = userRpcService.registerUser(phone);

                    if (Objects.isNull(userId)) {
                        throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                    }
                } else {
                    userId = userDO.getId();
                }
            }
            case PASSWORD -> {
                String password = userLoginReqVO.getPassword();
                FindUserByPhoneRespDTO userDO = userRpcService.findUserByPhone(phone);
                if (Objects.isNull(userDO)) {
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }

                String encodePassword = userDO.getPassword();
                if (!passwordEncoder.matches(password, encodePassword)) {
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }

                userId = userDO.getId();
            }
            default -> {
                throw new BizException(ResponseCodeEnum.LOGIN_TYPE_ERROR);
            }
        }

        // satoken登陆 , 并返回token令牌
        StpUtil.login(userId);

        SaTokenInfo saTokenInfo = StpUtil.getTokenInfo();

        return Response.success(saTokenInfo.getTokenValue());
    }

    @Override
    public Response<?> logout() {
        Long userId = LoginUserContextHolder.getUserId();
        log.info("==> 用户退出登录, userId: {}", userId);
        StpUtil.logout(userId);
        return Response.success();
    }

    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        String newPassword = updatePasswordReqVO.getNewPassword();
        String encodePassword = passwordEncoder.encode(newPassword);

        boolean result = userRpcService.updatePassword(encodePassword);

        if (!result) {
            throw new BizException(ResponseCodeEnum.SYSTEM_ERROR);
        }
        return Response.success();
    }
}
